﻿//DOES NOT YET WORK WITH CONSTRUCTORS

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using Gendarme.Rules.Smells;
using ICSharpCode.NRefactory.PrettyPrinter;

namespace Commander.Core.Refactorings.Modifiers {
	public class SpeculativeGeneralityModifer : NetWalkerCodeModifier {
		public IParser VariantParser { get; set; }
		TypeDeclaration m_type;
		List<INode> m_baseNodes;
		public string BaseName { get; private set; }
		public string VariantName { get; private set; }


		public SpeculativeGeneralityModifer(XElement extra, IParser baseParser)
			: base(extra, baseParser) {

			m_baseNodes = new List<INode>();
			BaseName = extra.Attribute(CommanderSerializer.NAME).Value;
			VariantName = extra.Attribute(CommanderSerializer.VARIANT).Value;

		}

		public override string ApplyModification() {
			if (VariantParser == null) {
				throw new ArgumentNullException("The parsewr for the variant class is null");
			}
			else {
				CompilationUnit cu = m_parser.CompilationUnit;
				cu.AcceptVisitor(this, null);

				cu = VariantParser.CompilationUnit;
				cu.AcceptVisitor(this, null);

				foreach (var node in m_baseNodes) {
					m_type.AddChild(node);
				}

				var baseClass = m_type.BaseTypes.Single(e => e.Type.Equals(BaseName));
				m_type.BaseTypes.Remove(baseClass);

				IOutputAstVisitor output = new CSharpOutputVisitor();
				cu.AcceptVisitor(output, null);
				return output.Text;
			}
		}


		public override object VisitMethodDeclaration(ICSharpCode.NRefactory.Ast.MethodDeclaration methodDeclaration, object data) {
			base.VisitMethodDeclaration(methodDeclaration, data);

			if ((methodDeclaration.Parent as TypeDeclaration).Name.Equals(BaseName)) {
				if (!methodDeclaration.Body.IsNull) {
					m_baseNodes.Add(methodDeclaration);
				}
			}
			else if ((methodDeclaration.Parent as TypeDeclaration).Name.Equals(VariantName)) {
				if (m_type == null) {
					m_type = methodDeclaration.Parent as TypeDeclaration;
				}

				if ((methodDeclaration.Modifier & ICSharpCode.NRefactory.Ast.Modifiers.Override) == ICSharpCode.NRefactory.Ast.Modifiers.Override) {
					methodDeclaration.Modifier = methodDeclaration.Modifier ^ ICSharpCode.NRefactory.Ast.Modifiers.Override;
				}

			}
			else {
			}

			return null;
		}

		public override object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data) {
			base.VisitFieldDeclaration(fieldDeclaration, data);
			if ((fieldDeclaration.Parent as TypeDeclaration).Name.Equals(BaseName)) {
				m_baseNodes.Add(fieldDeclaration);
			}

			return null;
		}

		public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data) {
			base.VisitPropertyDeclaration(propertyDeclaration, data);

			if ((propertyDeclaration.Parent as TypeDeclaration).Name.Equals(BaseName)) {
				m_baseNodes.Add(propertyDeclaration);
			}

			return null;
		}
	}
}
